package com.meshnetics.gb.stack.mac.type;

import com.meshnetics.gb.type.impl.ByteUtils;
import com.meshnetics.gb.type.impl.zcl.Bitmap;

/**
 * Bitmask for channels (can be considered as list of channels). Used in MACScanRequest and MACScanConfirm.
 * The channels are limited to ones in range [0x0b,0x1a]. Read-only.
 *
 * @author AKovylin
 */
public class ChannelMask extends Bitmap {
    public static final int MIN_CHANNEL = 0x0B;
    public static final int MAX_CHANNEL = 0x1A;

    public ChannelMask() {
        this(0);
    }

    public ChannelMask(int[] channels) {
        this();
        if (channels == null) {
            throw new NullPointerException("channels is null");
        }
        for (int i = 0; i < channels.length; i++) {
            if (channels[i] < MIN_CHANNEL || channels[i] > MAX_CHANNEL) {
                throw new IllegalArgumentException("invalid channel");
            }
            super.setBit(channels[i], true);
        }
    }

    public ChannelMask(int mask) {
        this(TypeChannelMask.TYPE, maskToBytes(mask));
    }

    public ChannelMask(byte[] mask) {
        this(TypeChannelMask.TYPE, mask);
    }

    ChannelMask(TypeChannelMask type, byte[] value) {
        super(type, value);
        if (value == null) {
            throw new NullPointerException("value is null");
        }
        if (value.length != 4) {
            throw new IllegalArgumentException("invalid value");
        }
        if (super.getBits(0, MIN_CHANNEL - 1) != 0 || super.getBits(MAX_CHANNEL + 1, 4 * 8) != 0) {
            throw new IllegalArgumentException("invalid channels specified");
        }
    }

    private static byte[] maskToBytes(int mask) {
        byte[] bmask = new byte[4];
        ByteUtils.fillFromLong(mask, bmask, 0, 4);
        return bmask;
    }

    public boolean getBit(int bit) {
        if (bit < MIN_CHANNEL || bit > MAX_CHANNEL) {
            throw new IllegalArgumentException("invalid channel");
        }
        return super.getBit(bit);
    }

    public int getBits(int fromBit, int toBit) {
        if (fromBit < MIN_CHANNEL || fromBit > MAX_CHANNEL) {
            throw new IllegalArgumentException("invalid fromBit");
        }
        if (toBit < MIN_CHANNEL || toBit > MAX_CHANNEL + 1) {
            throw new IllegalArgumentException("invalid toBit");
        }
        return super.getBits(fromBit, toBit);
    }

    public int[] getChannels() {
        int count = 0;
        for (int i = MIN_CHANNEL; i <= MAX_CHANNEL; i++) {
            if (super.getBit(i)) {
                count++;
            }
        }
        int res[] = new int[count];
        int index = 0;
        for (int i = MIN_CHANNEL; i <= MAX_CHANNEL; i++) {
            if (super.getBit(i)) {
                res[index++] = i;
            }
        }
        return res;
    }

    public boolean isEmpty() {
        boolean res = true;
        for (int i = 0; i < value.length; i++) {
            res = value[i] == 0x00;
            if (!res) {
                break;
            }
        }
        return res;
    }
}
